/* Copyright (c) HiSilicon (Shanghai) Technologies Co., Ltd. 2022-2024. All rights reserved.
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
 * Description: Application core main function for standard \n
 *
 * History: \n
 * 2022-07-27, Create file. \n
 */
#include "lwip/netifapi.h"
#include "lwip/sockets.h"
#include "securec.h"
#include "wifi_hotspot.h"
#include "wifi_hotspot_config.h"
#include "td_base.h"
#include "td_type.h"
#include "stdlib.h"
#include "app_init.h"
#include "soc_osal.h"

#include "ssd1306.h"
#include "key_value.h"
#include "web_server.h"
#include "nv_common_cfg.h"

#if defined(CONFIG_SAMPLE_SUPPORT_SLE_RGB_MASTER_SERVER)
#include "sle_server.h"
#elif defined(CONFIG_SAMPLE_SUPPORT_SLE_RGB_MASTER_CLIENT)
#include "sence.h"
#endif

#define RGB_MASTER_WIFI_SOFTAP_LOG "[WIFI_SOFTAP_CONNECT]"
#define RGB_MASTER_STA_LOG "[WIFI_STA_CONNECT]"
#define WIFI_IFNAME_MAX_SIZE 16
#define WIFI_MAX_KEY_LEN 65
#define WIFI_MAX_SSID_LEN 33

#define WIFI_TASK_PRIO 13
#define WIFI_TASK_DURATION_MS 2000
#define WIFI_TASK_STACK_SIZE 0x4000

#define WIFI_SCAN_AP_LIMIT 64
#define WIFI_MAC_LEN 6
#define WIFI_NOT_AVALLIABLE 0
#define WIFI_AVALIABE 1
#define WIFI_GET_IP_MAX_COUNT 300
#define WIFI_AP_TRY_CONNECT_MAX_COUNT 100

static td_void wifi_scan_state_changed(td_s32 state, td_s32 size);
static td_void wifi_connection_changed(td_s32 state, const wifi_linked_info_stru *info, td_s32 reason_code);

wifi_event_stru wifi_event_cb = {
    .wifi_event_connection_changed = wifi_connection_changed,
    .wifi_event_scan_state_changed = wifi_scan_state_changed,
};

enum {
    RGB_MASTER_STA_INIT = 0,     /* 0:初始态 */
    RGB_MASTER_STA_SCANING,      /* 1:扫描中 */
    RGB_MASTER_STA_SCAN_DONE,    /* 2:扫描完成 */
    RGB_MASTER_STA_FOUND_TARGET, /* 3:匹配到目标AP */
    RGB_MASTER_STA_CONNECTING,   /* 4:连接中 */
    RGB_MASTER_STA_CONNECT_DONE, /* 5:关联成功 */
    RGB_MASTER_STA_GET_IP,       /* 6:获取IP */
} g_wifi_state_enum;

static td_u8 g_wifi_state = RGB_MASTER_STA_INIT;
static td_u8 g_wifi_ap_no_find_count = 0;
static td_char g_expected_ssid[WIFI_MAX_SSID_LEN] = {0};
static td_char g_key[WIFI_MAX_KEY_LEN] = {0}; /* 待连接的网络接入密码 */

/*****************************************************************************
  Web配网部分
*****************************************************************************/
static rgb_master_wifi_info_t nv_wifi_info;

static int show_ip_to_oled(char *ip)
{
    char tmp_data[18];
    int x = 0;
    int y = 20;
    // Use space character to clear Oled display
    memset(tmp_data, CHAR_SPACE, MAX_FONT_7_10_IN_ONE_LINE);
    memcpy(tmp_data, ip, strlen(ip));
    tmp_data[MAX_FONT_7_10_IN_ONE_LINE] = CHAR_END;
    ssd1306_set_cursor(x, y);
    ssd1306_draw_string(tmp_data, g_font_7x10, WHITE);
    ssd1306_update_screen();
    osal_printk("%s::show_ip_to_oled done!.\r\n", RGB_MASTER_STA_LOG);
    free(tmp_data);
}

/*****************************************************************************
  STA 扫描事件回调函数
*****************************************************************************/
static td_void wifi_scan_state_changed(td_s32 state, td_s32 size)
{
    UNUSED(state);
    UNUSED(size);
    osal_printk("%s::Scan done!.\r\n", RGB_MASTER_STA_LOG);
    g_wifi_state = RGB_MASTER_STA_SCAN_DONE;
    return;
}

/*****************************************************************************
  STA 关联事件回调函数
*****************************************************************************/
static td_void wifi_connection_changed(td_s32 state, const wifi_linked_info_stru *info, td_s32 reason_code)
{
    UNUSED(info);
    UNUSED(reason_code);

    if (state == WIFI_NOT_AVALLIABLE) {
        osal_printk("%s::Connect fail!. try agin !\r\n", RGB_MASTER_STA_LOG);
        g_wifi_state = RGB_MASTER_STA_INIT;
    } else {
        osal_printk("%s::Connect succ!.\r\n", RGB_MASTER_STA_LOG);
        g_wifi_state = RGB_MASTER_STA_CONNECT_DONE;
    }
}

void print_wifi_info_test(const wifi_sta_config_stru *config)
{
    osal_printk("%s(%d)ssid: %s size(%d)\n", __FUNCTION__, __LINE__, config->ssid, strlen(config->ssid));
    osal_printk("%s(%d)bssid: %d size(%d)\n", __FUNCTION__, __LINE__, config->bssid, sizeof(config->bssid));
    osal_printk("%s(%d)pre_shared_key: %s size(%d)\n", __FUNCTION__, __LINE__, config->pre_shared_key,
                strlen(config->pre_shared_key));
    osal_printk("%s(%d)security_type: %d size(%d)\n", __FUNCTION__, __LINE__, config->security_type,
                sizeof(config->security_type));
    osal_printk("%s(%d)wifi_psk_type: %d size(%d)\n", __FUNCTION__, __LINE__, config->wifi_psk_type,
                sizeof(config->wifi_psk_type));
    osal_printk("%s(%d)strengthen_verify: %d size(%d)\n", __FUNCTION__, __LINE__, config->strengthen_verify,
                sizeof(config->strengthen_verify));
    osal_printk("%s(%d)channel: %d size(%d)\n", __FUNCTION__, __LINE__, config->channel, sizeof(config->channel));
    osal_printk("%s(%d)rsv: %d size(%d)\n", __FUNCTION__, __LINE__, config->rsv, sizeof(config->rsv));
    osal_printk("%s(%d)ip_type: %d size(%d)\n", __FUNCTION__, __LINE__, config->ip_type, sizeof(config->ip_type));
    osal_printk("%s(%d)static_ip_addr: %d size(%d)\n", __FUNCTION__, __LINE__, config->static_ip.ip_address,
                sizeof(config->static_ip.ip_address));
    osal_printk("%s(%d)static_ip_gateway: %d size(%d)\n", __FUNCTION__, __LINE__, config->static_ip.gateway,
                sizeof(config->static_ip.gateway));
    osal_printk("%s(%d)static_ip_dns_servers: %d size(%d)\n", __FUNCTION__, __LINE__, config->static_ip.dns_servers,
                sizeof(config->static_ip.dns_servers));
    osal_printk("%s(%d)static_ip_netmask: %d size(%d)\n", __FUNCTION__, __LINE__, config->static_ip.netmask,
                sizeof(config->static_ip.netmask));
    osal_printk("%s(%d)static_ipv6_addr: %s size(%d)\n", __FUNCTION__, __LINE__, config->static_ipv6.ipv6_address,
                strlen(config->static_ipv6.ipv6_address));
    osal_printk("%s(%d)static_ipv6_dns: %s size(%d)\n", __FUNCTION__, __LINE__, config->static_ipv6.ipv6_dns_servers,
                strlen(config->static_ipv6.ipv6_dns_servers));
}

/*****************************************************************************
  STA 匹配目标AP
*****************************************************************************/

/* 找到网络后复制网络信息和接入密码 */
td_s32 rgb_master_config_network_info(wifi_sta_config_stru *expected_bss, wifi_scan_info_stru *result, td_u8 bss_index)
{
    if (memcpy_s(expected_bss->ssid, WIFI_MAX_SSID_LEN, g_expected_ssid, strlen(g_expected_ssid)) != 0) {
        osal_kfree(result);
        osal_printk("%s function :%s, line:%d\r\n", RGB_MASTER_STA_LOG, __FUNCTION__, __LINE__);
        return -1;
    }
    if (memcpy_s(expected_bss->bssid, WIFI_MAC_LEN, result[bss_index].bssid, WIFI_MAC_LEN) != 0) {
        osal_kfree(result);
        osal_printk("%s function :%s, line:%d\r\n", RGB_MASTER_STA_LOG, __FUNCTION__, __LINE__);
        return -1;
    }
    expected_bss->security_type = result[bss_index].security_type;
    if (memcpy_s(expected_bss->pre_shared_key, WIFI_MAX_SSID_LEN, g_key, strlen(g_key)) != 0) {
        osal_kfree(result);
        osal_printk("%s function :%s, line:%d\r\n", RGB_MASTER_STA_LOG, __FUNCTION__, __LINE__);
        return -1;
    }
    expected_bss->ip_type = 1; /* 1：IP类型为动态DHCP获取 */
    osal_kfree(result);
    return 0;
}

td_s32 rgb_master_get_match_network(wifi_sta_config_stru *expected_bss)
{
    td_s32 ret;
    td_u32 num = 64; /* 64:扫描到的Wi-Fi网络数量 */
    td_bool find_ap = TD_FALSE;
    td_u8 bss_index;
    /* 获取扫描结果 */
    td_u32 scan_len = sizeof(wifi_scan_info_stru) * WIFI_SCAN_AP_LIMIT;
    wifi_scan_info_stru *result = osal_kmalloc(scan_len, OSAL_GFP_ATOMIC);
    if (result == TD_NULL) {
        return -1;
    }
    memset_s(result, scan_len, 0, scan_len);
    ret = wifi_sta_get_scan_info(result, &num);
    if (ret != 0) {
        osal_kfree(result);
        return -1;
    }
    memcpy_s(g_expected_ssid, WIFI_MAX_SSID_LEN, nv_wifi_info.ssid, strlen(nv_wifi_info.ssid));
    memcpy_s(g_key, WIFI_MAX_KEY_LEN, nv_wifi_info.password, strlen(nv_wifi_info.password));
    osal_printk("%s g_expected_ssid :%s, g_key:%s\r\n", RGB_MASTER_STA_LOG, g_expected_ssid, g_key);
    /* 筛选扫描到的Wi-Fi网络，选择待连接的网络 */
    for (bss_index = 0; bss_index < num; bss_index++) {
        if (strlen(g_expected_ssid) == strlen(result[bss_index].ssid)) {
            if (memcmp(g_expected_ssid, result[bss_index].ssid, strlen(g_expected_ssid)) == 0) {
                find_ap = TD_TRUE;
                break;
            }
        }
    }
    /* 未找到待连接AP,可以继续尝试扫描或者退出 */
    if (find_ap == TD_FALSE) {
        osal_kfree(result);
        osal_printk("%s function :%s, line:%d\r\n", RGB_MASTER_STA_LOG, __FUNCTION__, __LINE__);
        return -1;
    }
    ret = rgb_master_config_network_info(expected_bss, result, bss_index);
    if (ret != 0) {
        osal_printk("%s function :%s, line:%d Error\r\n", RGB_MASTER_STA_LOG, __FUNCTION__, __LINE__);
        return -1;
    }
    return 0;
}

/*****************************************************************************
  STA 关联状态查询
*****************************************************************************/
td_bool rgb_master_check_connect_status(td_void)
{
    td_u8 index;
    wifi_linked_info_stru wifi_status;
    /* 获取网络连接状态，共查询5次，每次间隔500ms */
    for (index = 0; index < 5; index++) {
        (void)usleep(50); /* 50: 延时500ms */
        memset_s(&wifi_status, sizeof(wifi_linked_info_stru), 0, sizeof(wifi_linked_info_stru));
        if (wifi_sta_get_ap_info(&wifi_status) != 0) {
            continue;
        }
        if (wifi_status.conn_state == 1) {
            return 0; /* 连接成功退出循环 */
        }
    }
    return -1;
}

/*****************************************************************************
  STA DHCP状态查询
*****************************************************************************/
td_bool rgb_master_check_dhcp_status(struct netif *netif_p, td_u32 *wait_count)
{
    char ip_str[16]; // 用于存储点分十进制格式的IP地址字符串
    if ((ip_addr_isany(&(netif_p->ip_addr)) == 0) && (*wait_count <= WIFI_GET_IP_MAX_COUNT)) {
        /* DHCP成功 */
        ip4addr_ntoa_r(
            &(netif_p->ip_addr), ip_str,
            sizeof(
                ip_str)); // 注意：这里假设存在一个ip4addr_ntoa_r函数，它是线程安全的，或者你可以使用非线程安全的ip4addr_ntoa但需要注意并发问题。
        // 或者，如果你的库没有提供这样的函数，你可能需要手动转换IP地址。
        osal_printk("%s::STA DHCP success, IP Address: %s\r\n", RGB_MASTER_STA_LOG, ip_str);
        show_ip_to_oled(ip_str);
        g_wifi_ap_no_find_count = 0;
        return 0;
    }

    if (*wait_count > WIFI_GET_IP_MAX_COUNT) {
        osal_printk("%s::STA DHCP timeout, try again !.\r\n", RGB_MASTER_STA_LOG);
        *wait_count = 0;
        g_wifi_state = RGB_MASTER_STA_INIT;
    }
    return -1;
}
td_s32 rgb_master_check_sta_connect(td_void)
{
    g_wifi_ap_no_find_count++;
    if (g_wifi_ap_no_find_count > WIFI_AP_TRY_CONNECT_MAX_COUNT) {
        // 超过100次未找到目标AP，则清除wifi信息，重启系统
        handle_clear_wifi();
    }
}

td_s32 rgb_master_sta_function(td_void)
{
    td_char ifname[WIFI_IFNAME_MAX_SIZE + 1] = "wlan0"; /* 创建的STA接口名 */
    struct netif *netif_p = TD_NULL;
    td_u32 wait_count = 0;
    static wifi_sta_config_stru expected_bss = {0}; /* 连接请求信息 */
    /* 创建STA接口 */
    if (wifi_sta_enable() != 0) {
        return -1;
    }
    do {
        (void)usleep(1); /* 1: 等待10ms后判断状态 */
        if (g_wifi_state == RGB_MASTER_STA_INIT) {
            g_wifi_state = RGB_MASTER_STA_SCANING;
            /* 启动STA扫描 */
            if (wifi_sta_scan() != 0) {
                g_wifi_state = RGB_MASTER_STA_INIT;
                continue;
            }
        } else if (g_wifi_state == RGB_MASTER_STA_SCAN_DONE) {
            /* 获取待连接的网络 */
            if (rgb_master_get_match_network(&expected_bss) != 0) {
                g_wifi_state = RGB_MASTER_STA_INIT;
                rgb_master_check_sta_connect();
                continue;
            }
            g_wifi_state = RGB_MASTER_STA_FOUND_TARGET;
        } else if (g_wifi_state == RGB_MASTER_STA_FOUND_TARGET) {
            g_wifi_state = RGB_MASTER_STA_CONNECTING;
            /* 启动连接 */
            if (wifi_sta_connect(&expected_bss) != 0) {
                g_wifi_state = RGB_MASTER_STA_INIT;
                continue;
            }
        } else if (g_wifi_state == RGB_MASTER_STA_CONNECT_DONE) {
            g_wifi_state = RGB_MASTER_STA_GET_IP;
            netif_p = netifapi_netif_find(ifname);
            if (netif_p == TD_NULL || netifapi_dhcp_start(netif_p) != 0) {
                g_wifi_state = RGB_MASTER_STA_INIT;
                continue;
            }
        } else if (g_wifi_state == RGB_MASTER_STA_GET_IP) {
            if (rgb_master_check_dhcp_status(netif_p, &wait_count) == 0) {
                break;
            }
            wait_count++;
        }
    } while (1);
    return 0;
}

/*****************************************************************************
  SoftAP功能
*****************************************************************************/
td_s32 rgb_master_softap_function(td_void)
{
/* SoftAp接口的信息 */
#if defined(CONFIG_SAMPLE_SUPPORT_SLE_RGB_MASTER_SERVER)
    td_char ssid[WIFI_MAX_SSID_LEN] = "RGB_Master_Server";
#elif defined(CONFIG_SAMPLE_SUPPORT_SLE_RGB_MASTER_CLIENT)
    td_char ssid[WIFI_MAX_SSID_LEN] = "RGB_Master_Client";
#endif
    td_char pre_shared_key[WIFI_MAX_KEY_LEN] = "1234567890";
    softap_config_stru hapd_conf = {0};
    softap_config_advance_stru config = {0};
    td_char ifname[WIFI_IFNAME_MAX_SIZE + 1] = "ap0"; /* 创建的SoftAp接口名 */
    struct netif *netif_p = TD_NULL;
    ip4_addr_t st_gw;
    ip4_addr_t st_ipaddr;
    ip4_addr_t st_netmask;
    IP4_ADDR(&st_ipaddr, 192, 168, 43, 1);   /* IP地址设置：192.168.43.1 */
    IP4_ADDR(&st_netmask, 255, 255, 255, 0); /* 子网掩码设置：255.255.255.0 */
    IP4_ADDR(&st_gw, 192, 168, 43, 2);       /* 网关地址设置：192.168.43.2 */

    /* 配置SoftAp基本参数 */
    (td_void) memcpy_s(hapd_conf.ssid, sizeof(hapd_conf.ssid), ssid, sizeof(ssid));
    (td_void) memcpy_s(hapd_conf.pre_shared_key, WIFI_MAX_KEY_LEN, pre_shared_key, WIFI_MAX_KEY_LEN);
    hapd_conf.security_type = 3; /* 3: 加密方式设置为WPA_WPA2_PSK */
    hapd_conf.channel_num = 13;  /* 13：工作信道设置为13信道 */
    hapd_conf.wifi_psk_type = 0;

    /* 配置SoftAp网络参数 */
    config.beacon_interval = 100; /* 100：Beacon周期设置为100ms */
    config.dtim_period = 2;       /* 2：DTIM周期设置为2 */
    config.gi = 0;                /* 0：short GI默认关闭 */
    config.group_rekey = 86400;   /* 86400：组播秘钥更新时间设置为1天 */
    config.protocol_mode = 4;     /* 4：协议类型设置为802.11b + 802.11g + 802.11n + 802.11ax */
    config.hidden_ssid_flag = 1;  /* 1：不隐藏SSID */
    if (wifi_set_softap_config_advance(&config) != 0) {
        return -1;
    }
    /* 启动SoftAp接口 */
    if (wifi_softap_enable(&hapd_conf) != 0) {
        return -1;
    }
    /* 配置DHCP服务器 */
    netif_p = netif_find(ifname);
    if (netif_p == TD_NULL) {
        (td_void) wifi_softap_disable();
        return -1;
    }
    if (netifapi_netif_set_addr(netif_p, &st_ipaddr, &st_netmask, &st_gw) != 0) {
        (td_void) wifi_softap_disable();
        return -1;
    }
    if (netifapi_dhcps_start(netif_p, NULL, 0) != 0) {
        (td_void) wifi_softap_disable();
        return -1;
    }
    osal_printk("%s::SoftAp start success.\r\n", RGB_MASTER_WIFI_SOFTAP_LOG);
    return 0;
}

int wifi_connect_init(void)
{
    uint16_t nv_wifi_info_len = 0;
    ssd1306_device_init();
    /* 注册事件回调 */
    if (wifi_register_event_cb(&wifi_event_cb) != 0) {
        osal_printk("%s::wifi_event_cb register fail.\r\n", RGB_MASTER_STA_LOG);
        return -1;
    }
    osal_printk("%s::wifi_event_cb register succ.\r\n", RGB_MASTER_STA_LOG);

    /* 等待wifi初始化完成 */
    while (wifi_is_wifi_inited() == 0) {
        (void)usleep(10); /* 1: 等待100ms后判断状态 */
    }
    osal_printk("%s::wifi init succ.\r\n", RGB_MASTER_WIFI_SOFTAP_LOG);

    (void)memset_s(&nv_wifi_info, sizeof(nv_wifi_info), 0, sizeof(nv_wifi_info));
    int ret = key_value_rgb_master_wifi_info_read((uint8_t *)&nv_wifi_info, &nv_wifi_info_len);

    osal_printk("%s::ret=0x%x nv_wifi_info_len %d ssid_len:%d passwd_len:%d\r\n", RGB_MASTER_WIFI_SOFTAP_LOG, ret,
                nv_wifi_info_len, strlen(nv_wifi_info.ssid), strlen(nv_wifi_info.password));
    if ((ret == 0) && (nv_wifi_info_len != 0) && (nv_wifi_info.ssid != TD_NULL) && (nv_wifi_info.password != TD_NULL) &&
        (strlen(nv_wifi_info.ssid) != 0) && (strlen(nv_wifi_info.password) != 0)) {
        osal_printk("%s::wifi ssid:%s passwd:%s\r\n", RGB_MASTER_WIFI_SOFTAP_LOG, nv_wifi_info.ssid,
                    nv_wifi_info.password);
        if (rgb_master_sta_function() != 0) {
            osal_printk("%s::rgb_master_sta_function fail.\r\n", RGB_MASTER_STA_LOG);
            return -1;
        }
    } else {
        if (rgb_master_softap_function() != 0) {
            osal_printk("%s::rgb_master_softap_function fail.\r\n", RGB_MASTER_WIFI_SOFTAP_LOG);
            return -1;
        }
        show_ip_to_oled("AP:192.168.43.1");
    }

    web_server_init();
    return 0;
}

void wifi_connect_entry(void)
{
    uint32_t ret;
    osal_task *taskid;
    // 创建任务调度
    osal_kthread_lock();
    // 创建任务1
    taskid =
        osal_kthread_create((osal_kthread_handler)wifi_connect_init, NULL, "wifi_cnonect_Task", WIFI_TASK_STACK_SIZE);
    ret = osal_kthread_set_priority(taskid, WIFI_TASK_PRIO);
    if (ret != OSAL_SUCCESS) {
        osal_printk("create wifi_cnonect_Task failed .\n");
    }
    osal_kthread_unlock();
}

app_run(wifi_connect_entry);